package com.aispeech.rcprvd.provider;

import android.app.Application;
import android.hardware.usb.UsbDevice;
import android.hardware.usb.UsbInterface;
import android.hardware.usb.UsbRequest;
import android.util.Log;

import com.aispeech.rcprvd.RemoteDevice;
import com.aispeech.rcprvd.jni.RcNativeProcessJni;
import com.aispeech.rcprvd.provider.base.HidDataProvider;
import com.aispeech.rcprvd.utils.RcPrvdConst;
import com.aispeech.rcprvd.utils.UsbCommUtils;

import java.nio.ByteBuffer;

public class NanoHidIntDataProvider extends HidDataProvider {
    private final String TAG = "HidIntProvider";

    private final int NANO_ENDPOINT_IN_ADDR = 130;
    private final int NANO_ENDPOINT_OUT_ADDR = 5;

    private RemoteDevice mRemoteDevice;

    private Runnable mIntReadRunnable = new Runnable() {
        @Override
        public void run() {
            isReading = true;
            boolean retQueue;
            ByteBuffer byteBuffer;
            int nativeRet;

            try {
                int inMax;
                UsbRequest mUsbRequest;
                synchronized (NanoHidIntDataProvider.this) {

                    if (null == mUsbEndpointIn) {
                        Log.e(TAG, "mIntReadRunnable: mUsbEndpointIn is null ");
                        return;
                    }

                    inMax = mUsbEndpointIn.getMaxPacketSize();
                    Log.d(TAG, "mIntReadRunnable: inMax = " + inMax);
                    byteBuffer = ByteBuffer.allocate(inMax);
//                byteBuffer = ByteBuffer.allocateDirect(inMax);
                    mUsbRequest = new UsbRequest();

                    boolean ret = mUsbRequest.initialize(mUsbDeviceConnection, mUsbEndpointIn);
                    if (!ret) {
                        Log.e(TAG, "mIntReadRunnable,mUsbRequest initialize err");
                        return;
                    }

                    nativeRet = RcNativeProcessJni.native_process_start(RcPrvdConst.RCDevSource.NANO_HID);
                    if (nativeRet != RcPrvdConst.ErrorCode.NO_ERROR) {
                        Log.w(TAG, "native start err:" + nativeRet);
                        return;
                    }
                }

                Log.d(TAG, "mIntReadRunnable start working ----------------------" + Thread.currentThread().getName() + " : " + Thread.currentThread().getId());
                while (isReading) {
                    retQueue = mUsbRequest.queue(byteBuffer, inMax);
                    if (retQueue && (null != mUsbDeviceConnection) && (mUsbDeviceConnection.requestWait() == mUsbRequest)) {
                        feedNativeBuffer(byteBuffer.array());
                    } else {
                        Log.e(TAG, "mIntReadRunnable : error ");
                        break;
                    }
                }

                mUsbRequest.cancel();
                mUsbRequest.close();

                if (null != mUsbDeviceConnection) {
                    mUsbDeviceConnection.close();
                    mUsbDeviceConnection = null;
                }

                nativeRet = RcNativeProcessJni.native_process_stop(RcPrvdConst.RCDevSource.NANO_HID);
                Log.d(TAG, "stop: native stop ret = " + nativeRet);
                if (nativeRet != RcPrvdConst.ErrorCode.NO_ERROR) {
                    Log.w(TAG, "native stop err:" + nativeRet);
                }
            } catch (Exception e) {
                e.printStackTrace();
            }

            isReading = false;
            Log.d(TAG, "mIntReadRunnable stop working ----------------------" + Thread.currentThread().getName() + " : " + Thread.currentThread().getId());
        }
    };

    private void feedNativeBuffer(byte[] array) {
        RcNativeProcessJni.native_process_feed(RcPrvdConst.RCDevSource.NANO_HID, array, array.length);
    }

    public NanoHidIntDataProvider(Application appContext, RemoteDevice remoteDevice) {
        super(appContext);
        mRemoteDevice = remoteDevice;
    }

    @Override
    public int start() {
        super.start();
        Log.d(TAG, "start: ");
        if (null == mUsbDevice) {
            Log.e(TAG, "start: Usb Device is null , check usb connect state");
            return RcPrvdConst.ErrorCode.NO_DEVICE_FOUND;
        }
        if (isReading) {
            Log.w(TAG, "start: already reading");
            return RcPrvdConst.ErrorCode.ALREADY_RUNNING;
        }
        if (isPermissionGrant) {
            mHandler.post(mIntReadRunnable);
        } else {
            mHandler.post(mPermissionCheckRunnable);
            return RcPrvdConst.ErrorCode.NO_PERMISSION;
        }
        return RcPrvdConst.ErrorCode.NO_ERROR;
    }

    @Override
    public int stop() {
        super.stop();
        Log.d(TAG, "stop: ");
        if (isReading) {
            tryBreakRequestWait();
        }
        isReading = false;
        return RcPrvdConst.ErrorCode.NO_ERROR;
    }

    @Override
    public UsbDevice obtainUsbDevice() {
        if (null != mRemoteDevice) {
            return UsbCommUtils.getUsbDevice(mAppContext, mRemoteDevice.getVid(), mRemoteDevice.getPid());
        }
        return null;
    }

    @Override
    public UsbInterface obtainTransferInterface() {
        Log.d(TAG, "obtainTransferInterface: ");
        return UsbCommUtils.getInterfaceByAddr(mUsbDevice, NANO_ENDPOINT_IN_ADDR);
    }
}
